#pragma once
#include <core/strings/string_page.h>
#include <qbprotocol/include/SSCFETSModel.h>

#include <algorithm>
#include <map>
#include <vector>

#include "BrokerKeyInfo.h"

using namespace std;

#define BASSERTS  //

struct ColumnOrder {
  int comlumn;
  bool ascend;
};

class CBondSortManager;
typedef int (*FieldComparator)(const void* f1, const void* f2);
struct FieldInfo {
  int sort_type;  // 排序类型,取值为kSortType
  int column_id;  // 列编号,VSortKey,实际上是列对应的全局排序key
  int field_bytes;             // 该列字段占用字节数
  FieldComparator comparator;  // 该字段的比较器
  const char* column_name;     // 用于调试用,保存列名称
};

typedef std::map<int, FieldInfo> FiledInfoMap;
typedef std::map<int, FieldComparator> ComparatorMap;
class S_BONDLIB_EXPORT CBondUtil {
 public:
  static double GetBuyPrice(const BrokerKey& key);
  static double GetBuyNetPrice(const BrokerKey& key);
  static double GetSellPrice(const BrokerKey& key);
  static double GetSellNetPrice(const BrokerKey& key);
  static double GetModifyTime(const BrokerKey& key);
  static REPORT* GetCompanyInfoById(const std::string& szKey,
                                    const BrokerKey& szID);
  static double GetCFETSModifyTime(const BrokerKey& key);
  static CFETSQUOTE* GetCFETSQuoteById(const BrokerKey& key, BYTE btSettlement);
  static double GetCFETSRawDouble(const BrokerKey& key, int kPrcType,
                                  BYTE btSettlement);
  static xQBCFETSDealAllUnit* GetCFETSDealById(const BrokerKey& key);
  // 清算速度相关
  static double GetBuyPriceBySettlement(const BrokerKey& key,
                                        BYTE btSettlement);
  static double GetBuyNetPriceBySettlement(const BrokerKey& key,
                                           BYTE btSettlement);
  static double GetBuyFullPriceBySettlement(const BrokerKey& key,
                                            BYTE btSettlement);
  static double GetSellPriceBySettlement(const BrokerKey& key,
                                         BYTE btSettlement);
  static double GetSellNetPriceBySettlement(const BrokerKey& key,
                                            BYTE btSettlement);
  static double GetSellFullPriceBySettlement(const BrokerKey& key,
                                             BYTE btSettlement);
  static double GetModifyTimeBySettlement(const BrokerKey& key,
                                          BYTE btSettlement);
  static REPORT* GetCompanyInfoByIdAndSettlement(const std::string& szKey,
                                                 const BrokerKey& szID,
                                                 BYTE btSettlement);
};
class CBondSorter {  // 轻量级排序类

  enum kOrderChange {     // 列排序规则是否变化
    kOrderChangeSame,     // 列规则无变化,无须重新排序
    kOrderChangeReverse,  // 列规则只有一个列排序,且是反向,只需要将原先结果反序即可
    kOrderChangeReorder,  // 列规则需要重新排序
  };

 public:
  struct SortInfo {
    int sort_type;    // 排序类型,列排序产生的数据如何比较
    int column_id;    // 列编号,该列的排序用的数据如何产生
    int field_bytes;  // 该列排序产生的数据占用字节数
    FieldComparator comparator;  // 该字段的比较器,通用比较器只比较递增
    int offset;                  // 该字段在该记录中的偏移位置
    bool ascend;                 // 递增排序,递减排序
  };

 public:
 protected:
  vector<SortInfo> m_sortinfos;  // 多重排序,大多数情况下只有一个
  int m_record_size;             // 一条记录的字节
  int m_record_head_size;        // 一条记录的头部大小
  CBondSortManager* m_sort_manager;  // 持有的一个指针
  char* m_buffer;                    // 全排后的所有排序记录的内存
  int m_capcity;                     // m_buffer 的实际内存大小
 public:
  CBondSorter();
  ~CBondSorter();
  int GetRecordSize() const { return m_record_size; }

  //==============================================================================
  // Summary:
  //     -compare two BrokerKey
  // Parameters:
  //     -k1		: first BrokerKey
  //     -k2		: last BrokerKey
  // Return:
  //		-1	means k1<k2
  //		0	means k1==k2
  //		1	means k1>k2
  // Remarks:
  //     -
  // Usage:
  //     -compare two BrokerKey and decide where to insert so as to keep
  //     container ordered -used in JumpList::Comparator
  //==============================================================================
  int CompareRecordDirectly(const BrokerKeyInfo& k1, const BrokerKeyInfo& k2);

  //==============================================================================
  // Summary:
  //     -sort BrokerKey
  // Parameters:
  //     -orders	: come from CSortInfoManager,multi column sort info
  //     -keys	: array of BrokerKey to be sorted
  //     -ncorpid	: need when sort
  //     (kTknCleanPrice|kTknYield|kCleanPriceDiv|kYieldDiv|VTKNPRICE) -force
  //     : always sort
  // Return:
  //     -
  // Remarks:
  //     -when sort bond records,CBondSorter build each short record by orders
  //     -each short record is made up of one BrokerKeyInfo struct and several
  //     fixed bytes -of field of CBondInfo.These field data is accessed by
  //     BondReader::GetRecordField -Each field's size of memory is set by
  //     SetField.The short record's size can be calculated -by:
  //     sizeof(BrokerKeyInfo)+SUM(m_fields[column].field_bytes)
  // Usage:
  //     -rebuild orders of large array of BrokerKey
  //==============================================================================
  void Sort(const std::vector<ColumnOrder>& orders,
            std::vector<BrokerKeyInfo>& keys, int ncorpid, bool force = false);
  void Sort(const std::vector<ColumnOrder>& orders,
            std::vector<BrokerKeyInfo>& keys, BYTE btSettlement, int ncorpid,
            bool force = false);

  kOrderChange SetSortInfo(const std::vector<ColumnOrder>& orders);

  bool GetRecordField(const BrokerKey& key, int col, char* field, int capcity);
};

enum kCompDataType {
  kCompDataTypeString,
  kCompDataTypeDouble,
  kCompDataTypeInt,
  kCompDataTypeTime,
};

/*
        此类是用于表格的记录的通用排序类
*/
class S_BONDLIB_EXPORT BondSortBuffer {
  typedef qb::base::StringPage StringPage;

 public:
  struct INDEX {
    int index;   // 通常是要排序的整数值,如债券索引
    int offset;  // 对应记录在排序表内存m_buffer中的偏移量
    INDEX(int i, int o) : index(i), offset(o) {}
  };
  // 示范的Sort的模板参数所必须实现的3个接口
  class FieldReader {
   public:
    virtual ~FieldReader() {}
    virtual double GetDouble(int bondIndex, int columnId) = 0;
    virtual int GetInt(int bondIndex, int columnId) = 0;
    virtual time_t GetTime(int bondIndex, int columnId) = 0;
    virtual int GetString(int bondIndex, int columnId, char* buf,
                          int capcity) = 0;
  };

 protected:
  struct SortInfo {
    kCompDataType sort_type;  // 排序类型,列排序产生的数据如何比较
    int column_id;    // 列编号,该列的排序用的数据如何产生
    int field_bytes;  // 该列排序产生的数据占用字节数
    FieldComparator comparator;  // 该字段的比较器,通用比较器只比较递增
    int offset;   // 该字段在该记录中的偏移位置,不是整体的
    bool ascend;  // 递增排序,递减排序
  };
  class OneColumnAscendComp {
    char* m_buffer;          //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnAscendComp(char* buf, int offset, FieldComparator comp)
        : m_comp(comp), m_buffer(buf + offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) < 0;
    }
  };
  class OneColumnDescentComp {
    char* m_buffer;          //
    FieldComparator m_comp;  // 该字段的比较器,通用比较器只比较递增
   public:
    OneColumnDescentComp(char* buf, int offset, FieldComparator comp)
        : m_comp(comp), m_buffer(buf + offset) {}
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_comp(m_buffer + k1.offset, m_buffer + k2.offset) > 0;
    }
  };
  class MultiColComp {
    BondSortBuffer* m_sortbuf;

   public:
    MultiColComp(BondSortBuffer* sb) : m_sortbuf(sb) {};
    inline bool operator()(const INDEX& k1, const INDEX& k2) {
      return m_sortbuf->CompRecord(k1, k2) < 0;
    }
  };

  vector<SortInfo> m_sorts;  // 排序列,通常是2列,第一个是bonds的索引
  vector<INDEX> m_indexes;  // 要排序的记录,每个只有
  int m_record_size;        // 排序表的单条记录的尺寸
  int m_capcity;            // m_buffer的实际容量
  char* m_buffer;  // 排序表,每条记录尺寸都是固定大小不变
  StringPage m_str_page;  // 存储一次性排序过程中用到的字符串
 public:
  BondSortBuffer();
  ~BondSortBuffer();
  bool AddField(int id, kCompDataType type, bool ascend,
                FieldComparator cmp = nullptr);
  void Reset();
  // 序函数版本,和模板版本,代码一样
  void Sort(vector<int>& bonds, FieldReader* reader);

  // 模板版本,为了更好的性能和更大的灵活性
  template <class READER>
  void SortT(vector<int>& bonds, READER* reader) {
    if (bonds.size() <= 1 || m_sorts.size() <= 0) return;

    Prepare(bonds.size());
    m_str_page.Reset();
    m_indexes.clear();

    int offset = 0;
    m_indexes.clear();
    m_indexes.reserve(bonds.size());

    // 采集数据
    int slen = 0;
    char* record = m_buffer;
    const char* pstr = nullptr;
    char svalue[256] = {0};
    for (int i = 0; i < (int)bonds.size(); i++) {
      record = m_buffer + offset;
      m_indexes.push_back(INDEX(bonds[i], offset));
      for (int c = 0; c < (int)m_sorts.size(); c++) {
        const SortInfo& info = m_sorts[c];
        kCompDataType type = (kCompDataType)info.sort_type;
        switch (type) {
          case kCompDataTypeString:
            slen = reader->GetString(bonds[i], info.column_id, svalue,
                                     _countof(svalue));
            pstr = m_str_page.AddString(svalue, slen);
            memcpy(record + info.offset, &pstr, sizeof(const char*));
            break;
          case kCompDataTypeDouble:
            *((double*)(record + info.offset)) =
                reader->GetDouble(bonds[i], info.column_id);
          case kCompDataTypeInt:
            *((int*)(record + info.offset)) =
                reader->GetInt(bonds[i], info.column_id);
            break;
          case kCompDataTypeTime:
            *((time_t*)(record + info.offset)) =
                reader->GetTime(bonds[i], info.column_id);
            break;
        }
      }
      offset += m_record_size;
    }
    BASSERTS(offset == m_record_size * bonds.size() && offset <= m_capcity, "");

    // 排序并收集结果
    if (m_sorts.size() == 1) {
      const SortInfo& si = m_sorts[0];
      if (si.ascend)
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnAscendComp(m_buffer, si.offset, si.comparator));
      else
        std::sort(m_indexes.begin(), m_indexes.end(),
                  OneColumnDescentComp(m_buffer, si.offset, si.comparator));
    } else
      std::sort(m_indexes.begin(), m_indexes.end(), MultiColComp(this));
    bonds.clear();
    for (int i = 0; i < (int)m_indexes.size(); i++)
      bonds.push_back(m_indexes[i].index);
  }

 public:
  int CheckSort() const;
  int CompRecord(const INDEX& k1, const INDEX& k2) const;

 protected:
  void Prepare(int count);
  int FindExist(int id) const;
};
